﻿using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Xml;
using log4net;
using System.Runtime.InteropServices;
using System.Collections.Specialized;
using System.Threading;

namespace UPNP.IO
{
    public partial class DeviceService : DynamicObject
	{
        private static readonly ILog _logIO = LogManager.GetLogger(typeof(DeviceService).FullName + "-IO"); // IO log

        private readonly ILog _log = LogManager.GetLogger(typeof(DeviceService));
        private readonly Device _parentDevice;
        private readonly DeviceDom.Service _serviceDom;
        private readonly HybridDictionary _expressionCache = new HybridDictionary();
        private readonly Lazy<string[]> _allDynamicMemberNames;

        public string Id
        {
            get { return _serviceDom.ServiceName; }
        }

        public string ServiceTypeIdentifier
        {
            get { return _serviceDom.ServiceTypeId; }
        }

		public Device ParentDevice
		{
			get { return _parentDevice; }
		}

		public bool ConnectionLost
		{
			get { return _parentDevice.RootDevice.ConnectionLost; }
		}

		/// <summary>
		/// downloads the device schema of the
		/// hosting device
		/// </summary>
		public DeviceSchema GetSchema()
		{
			return _parentDevice.RootDevice.GetSchema();
		}

        public override IEnumerable<string> GetDynamicMemberNames()
        {
            return _allDynamicMemberNames.Value;
        }

        protected virtual void OnVariableChanged(DeviceService service, string variableName, object newValue)
        {
            if (_logIO.IsDebugEnabled)
            {
                _logIO.DebugFormat(
                    "State variable changed on service {0} ({1}): \"{2}\"=\"{3}\"",
                    service.Id,
                    service.ServiceTypeIdentifier,
                    variableName,
                    newValue
                    );
            }
        }

		internal DeviceService(Device parent, DeviceDom.Service service)
		{
			if (parent == null)
				throw new ArgumentNullException("parent");

            if (service == null)
                throw new ArgumentNullException("service");

            _parentDevice = parent;
		    _serviceDom = service;

            // prepare cached values
            _allDynamicMemberNames = new Lazy<string[]>(
                () => (
                    from a in _serviceDom.StateVariables
                    select a.VariableName
                ).Union(
                    from a in _serviceDom.Actions
                    select a.ActionName
                ).ToArray(),
                false
                );
		}

    }
}
